package com.sinosoft.hydra.um.services;

import com.sinosoft.hydra.um.condition.SearchDirectoryCondition;
import com.sinosoft.hydra.um.constant.BaseConstant;
import com.sinosoft.hydra.um.domain.model.DirectoryType;
import com.sinosoft.hydra.um.domain.permission.TDevice;
import com.sinosoft.hydra.um.domain.permission.TDirectory;
import cn.com.sinux.spring.exception.BusinessException;
import cn.com.sinux.spring.exception.ServiceException;
import com.sinosoft.hydra.um.repositories.TDirectoryDAO;
import cn.com.sinux.spring.utils.CodeUtils;
import cn.com.sinux.spring.utils.SpecificationHelper;
import cn.com.sinux.spring.utils.ValidatorUtils;;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

/**
 * Created by zyd on 2015/8/19.
 * 数据字典的维护
 */
@Service
@Transactional
public class DirectoryService {


    @Autowired
    private TDirectoryDAO tDirectoryDAO;


    /**
     * 根据字典类型
     *
     * @param directoryType
     * @param keycode
     * @return
     */
    public TDirectory findByKey(final DirectoryType directoryType, final String keycode) {
        if(!directoryType.isSingle() && StringUtils.isBlank(keycode)){
            return null;
        }
        Specification<TDirectory> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDirectory>() {
            public void fillParam(Root<TDirectory> root, CriteriaBuilder cb, List<Predicate> list) {
                final Path<String> group = root.get("dirGroup");
                final Path<String> _keycode = root.get("dirCode");
                list.add(cb.equal(group.as(String.class), directoryType.name()));
                if(!directoryType.isSingle()){
                    list.add(cb.equal(_keycode.as(String.class), keycode));
                }
            }
        });
        List<TDirectory> directories = tDirectoryDAO.findAll(specification);
        return directories.isEmpty() ? null : directories.get(0);
    }

    /**
     * 保存数据字典变量
     *
     * @param tDirectory
     */
    @Transactional
    public TDirectory addDirectory(TDirectory tDirectory) {
        DirectoryType directoryType = DirectoryType.valueOf(tDirectory.getDirGroup());
        if (directoryType == null) {
            throw new ServiceException("没有选择所属字典组");
        }
        if (StringUtils.isBlank(tDirectory.getDirCode())) {
            tDirectory.setDirCode(tDirectory.getDirGroup().toLowerCase().replace("_", "-")
                    + "C" + DateFormatUtils.format(Calendar.getInstance(), "yyyyMMdd") + CodeUtils.getRandomCode((int)Math.pow(10, 5)));
        }
        if (!directoryType.isSingle() && findByKey(DirectoryType.valueOf(tDirectory.getDirGroup()), tDirectory.getDirCode()) != null) {
            throw new BusinessException("yao.tian.jia.de.shu.ju.zi.dian.yi.jing.cun.zai.qing.xiu.gai.bian.ma.hou.zhong.xin.bao.cun");
        }
        if (tDirectory.getDirOrder() == null) {
            tDirectory.setDirOrder(0);
        }
        if (directoryType.isSingle()) {
            List<TDirectory> directories = findDirectories(directoryType);
            tDirectoryDAO.delete(directories);
        }
        tDirectory.setDisplay(directoryType.isDisplay() ? BaseConstant.INTEGER_TRUE : BaseConstant.INTEGER_FALSE);
        tDirectoryDAO.save(tDirectory);
        return tDirectory;
    }

    /**
     * 保存数据字典变量
     *
     * @param directoryType
     * @param value
     */
    @Transactional
    public TDirectory addDirectory(DirectoryType directoryType, String value) {
        TDirectory directory = new TDirectory();
        directory.setDirCode(directoryType.getDirGroup().toLowerCase().replace("_", "-")
                + "C" + DateFormatUtils.format(Calendar.getInstance(), "yyyyMMdd") + CodeUtils.getRandomCode(5));
        directory.setDirOrder(0);
        if (directoryType.isSingle()) {
            List<TDirectory> directories = findDirectories(directoryType);
            tDirectoryDAO.delete(directories);
        }
        directory.setDirGroup(directoryType.getDirGroup());
        directory.setDirValue(value);
        directory.setDisplay(directoryType.isDisplay() ? BaseConstant.INTEGER_TRUE : BaseConstant.INTEGER_FALSE);
        tDirectoryDAO.save(directory);
        return directory;
    }

    /**
     * 查询单个数据字典
     *
     * @param id
     * @return
     */
    public TDirectory findOne(String id){
        return StringUtils.isBlank(id) ? null : tDirectoryDAO.findOne(id);
    }

    /**
     * 保存数据字典变量
     *
     * @param tDirectory
     */
    @Transactional
    public TDirectory updateDirectory(TDirectory tDirectory) {
        TDirectory db = tDirectoryDAO.findOne(tDirectory.getId());
        if (db == null) {
            throw new ServiceException("没有传入正确的数据字典项参数");
        }
        DirectoryType directoryType = DirectoryType.valueOf(db.getDirGroup());
        tDirectory.setDirGroup(db.getDirGroup());
        if (StringUtils.isBlank(tDirectory.getDirCode())) {
            tDirectory.setDirCode(tDirectory.getDirGroup() + "C" + DateFormatUtils.format(Calendar.getInstance(), "yyyyMMdd") + CodeUtils.getRandomCode(5));
        }
        if (!tDirectory.getDirCode().equals(db.getDirCode())
                && findByKey(DirectoryType.valueOf(tDirectory.getDirGroup()), tDirectory.getDirCode()) != null) {
            throw new BusinessException("yao.tian.jia.de.shu.ju.zi.dian.yi.jing.cun.zai.qing.xiu.gai.bian.ma.hou.zhong.xin.bao.cun");
        }
        if (tDirectory.getDirOrder() == null) {
            tDirectory.setDirOrder(0);
        }
        tDirectory.setDisplay(directoryType.isDisplay() ? BaseConstant.INTEGER_TRUE : BaseConstant.INTEGER_FALSE);
        ValidatorUtils.checkBean(tDirectory);
        tDirectoryDAO.save(tDirectory);
        return tDirectory;
    }

    /**
     * 根据累心个查询数据字典
     *
     * @param directoryType
     * @return
     */
    @Transactional(readOnly = true)
    public List<TDirectory> findDirectories(DirectoryType directoryType) {
        SearchDirectoryCondition searchDirectoryCondition = new SearchDirectoryCondition();
        searchDirectoryCondition.setDirGroup(directoryType.name());
//        searchDirectoryCondition.setDisplay(BaseConstant.INTEGER_FALSE);
        return findDirectoriesByPage(searchDirectoryCondition, null).getContent();
    }

    /**
     * 根据ID集合查询数据字典
     *
     * @param ids
     * @return
     */
    @Transactional(readOnly = true)
    public List<TDirectory> findDirectories(final List<String> ids) {
        return ValidatorUtils.isArrayNotEmpty(ids)
                ? tDirectoryDAO.findAll(ids)
                : Collections.<TDirectory>emptyList();
    }

    /**
     * 根据条件查询数据字典
     *
     * @param searchDirectoryCondition
     * @return
     */
    @Transactional(readOnly = true)
    public Page<TDirectory> findDirectoriesByPage(SearchDirectoryCondition searchDirectoryCondition, Pageable pageable) {
        final SearchDirectoryCondition condition = searchDirectoryCondition == null ? new SearchDirectoryCondition() : searchDirectoryCondition;
        Specification<TDirectory> directorySpecification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDirectory>() {
            public void fillParam(Root<TDirectory> root, CriteriaBuilder cb, List<Predicate> list) {
                if (StringUtils.isNotBlank(condition.getDirGroup())) {
                    list.add(cb.equal(root.get("dirGroup").as(String.class), condition.getDirGroup()));
                }
                if (StringUtils.isNotBlank(condition.getDirValue())) {
                    list.add(cb.like(root.get("dirValue").as(String.class), "%" + condition.getDirValue() + "%"));
                }
                if (StringUtils.isNotBlank(condition.getDirCode())) {
                    list.add(cb.like(root.get("dirCode").as(String.class), condition.getDirCode()));
                }
                if (condition.getDisplay() != null) {
                    list.add(cb.equal(root.get("display").as(Integer.class), condition.getDisplay()));
                }
                if (condition.getDirectoryType() != null && StringUtils.isNotBlank(condition.getDirectoryType().getDirGroup())){
                    list.add(cb.equal(root.get("dirGroup").as(String.class), condition.getDirectoryType().getDirGroup()));
                }
            }
        });
        return tDirectoryDAO.findAll(directorySpecification, pageable);
    }

    /**
     * 获取数据字典根据order排序
     *
     * @param directoryType 类型
     * @return
     */
    @Transactional(readOnly = true)
    public List<TDirectory> findDirectoriesByOrder(final DirectoryType directoryType) {
        Specification<TDirectory> directorySpecification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDirectory>() {
            public void fillParam(Root<TDirectory> root, CriteriaBuilder cb, List<Predicate> list) {
                final Path<String> group = root.get("dirGroup");
                list.add(cb.equal(group.as(String.class), directoryType.name()));
            }
        });
        Sort sort = new Sort(Sort.Direction.ASC, "dirOrder", "id");
        return tDirectoryDAO.findAll(directorySpecification, sort);
    }

    /**
     * 根据跟组查询数据字典
     *
     * @param directoryGroup
     * @return
     */
    @Transactional(readOnly = true)
    public List<TDirectory> findDirectories(final String directoryGroup) {
        if (StringUtils.isBlank(directoryGroup)) {
            return Collections.emptyList();
        }
        DirectoryType directoryType = DirectoryType.valueOf(directoryGroup);
        return findDirectories(directoryType);
    }


    /**
     * 根据dirGroup和dirValue查找字典
     *
     * @param directoryType
     * @param dirValue
     * @return
     */
    @Transactional(readOnly = true)
    public TDirectory findDirectories(final DirectoryType directoryType, final String dirValue) {
        Specification<TDirectory> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDirectory>() {
            public void fillParam(Root<TDirectory> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("dirGroup").as(String.class), directoryType.name()));
                list.add(cb.equal(root.get("dirValue").as(String.class), dirValue));
            }
        });
        return tDirectoryDAO.findOne(specification);
    }

    /**
     * 根据dirGroup和dirValue查找字典
     *
     * @param directoryType
     * @param dirValue
     * @return
     */
    @Transactional(readOnly = true)
    public TDirectory findDirectories(final String directoryType, final String dirValue) {
        Specification<TDirectory> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDirectory>() {
            public void fillParam(Root<TDirectory> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("dirGroup").as(String.class), directoryType));
                list.add(cb.equal(root.get("dirValue").as(String.class), dirValue));
            }
        });
        List<TDirectory> list = tDirectoryDAO.findAll(specification);
        return list == null || list.size() == 0 ? null : list.get(0);
    }

    /**
     * 获取单个数据字典项
     *
     * @param id
     * @return
     */
    @Transactional(readOnly = true)
    public TDirectory getOne(String id) {
        TDirectory directory = StringUtils.isBlank(id)
                ? null
                : tDirectoryDAO.findOne(id);
        if (directory != null) {
            directory.setDirectoryType(DirectoryType.valueOf(directory.getDirGroup()));
        }
        return directory;
    }


    /**
     * 删除数据字典
     *
     * @param ids
     */
    @Transactional
    public List<TDirectory> deleteDirectories(List<String> ids) {
        List<TDirectory> directories = tDirectoryDAO.findAll(ids);
        tDirectoryDAO.delete(directories);
        return directories;
    }


    /**
     * 删除数据字典
     *
     * @param id
     */
    @Transactional
    public void deleteDirectory(String id) {
        TDirectory directory = getOne(id);
        if (directory == null) {
            return;
        }
        tDirectoryDAO.delete(id);
    }
}
